package com.syt.suan.system.service.impl;

import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.syt.suan.common.core.domain.R;
import com.syt.suan.common.core.enums.ResultCode;
import com.syt.suan.common.jwt.Jwt;
import com.syt.suan.common.redis.service.RedisService;
import com.syt.suan.system.config.token.CacheConstant;
import com.syt.suan.system.config.token.PayLoadConstant;
import com.syt.suan.system.domain.dos.UserDO;
import com.syt.suan.system.domain.bos.token.UserLoginTokenPayload;
import com.syt.suan.system.mapper.UserMapper;
import com.syt.suan.system.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.syt.suan.system.util.BCryptUtil;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 管理端用户表 服务实现类
 * </p>
 *
 * @author chen
 * @since 2024-12-04
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {

    @Value("${jwt.secret}")
    private String secret;

    @Resource
    private RedisService redisService;

    @Override
    public R<?> login(String userAccount, String password) {
        // 查询账号
        UserDO userDO = this.baseMapper.selectOne(Wrappers.<UserDO>lambdaQuery()
                .select(UserDO::getUserId, UserDO::getNickName, UserDO::getPassword)
                .eq(UserDO::getUserAccount, userAccount)
        );
        // 查询失败
        if (userDO == null) {
            return R.failed().code(ResultCode.FAILED_USER_NOT_EXISTS);
        }

        // 判断密码
        boolean isPass = BCryptUtil.matchesPassword(password, userDO.getPassword());
        // 密码错误
        if (!isPass) {
            return R.failed().code(ResultCode.FAILED_LOGIN);
        }


        // 创建 user token payload
        UserLoginTokenPayload userLoginTokenPayload = new UserLoginTokenPayload();
        userLoginTokenPayload.setUserId(userDO.getUserId());
        userLoginTokenPayload.setNickName(userDO.getNickName());

        // 生成 Claims
        Map<String, Object> claims = new HashMap<>();
        claims.put(PayLoadConstant.USER_ID, userLoginTokenPayload.getUserId());

        // 构建 redis user 唯一键
        String redisUserKey = UUID.fastUUID().toString();

        // 将唯一键也存入 claims 中，稍后一起设置进 token payload
        claims.put(PayLoadConstant.REDIS_USER_KEY, redisUserKey);

        // 生成 token
        String token = Jwt.createToken(claims, secret);

        // 将 user redis 对应 value 存入 redis 中
        redisService.setCacheObject(
                CacheConstant.LOGIN_TOKEN_KEY_PREFIX +
                        redisUserKey,
                token,
                CacheConstant.EXPIRATION, TimeUnit.MINUTES
        );


        // 登录成功，返回用户信息 / Token
        return R.success().msg("登录成功").data(token);
    }

    @Override
    public R<?> add(String userAccount, String password, String nickName, Long createBy) {
        // 账号是否已存在
        // 查询账号
        UserDO userDO = this.baseMapper.selectOne(Wrappers.<UserDO>lambdaQuery()
                .select(UserDO::getUserId, UserDO::getNickName, UserDO::getPassword)
                .eq(UserDO::getUserAccount, userAccount)
        );
        // 查询成功 账号已存在
        if (userDO != null) {
            return R.failed().code(ResultCode.AILED_USER_EXISTS);
        }
        // 查询失败 账号不存在
        // 构建 UserDO 对象
        UserDO newUserDO = new UserDO();
        newUserDO.setUserAccount(userAccount);
        // BCrypt 密码加密
        newUserDO.setPassword(BCryptUtil.encryptPassword(password));
        // 判断昵称是否为空
        // 不为空
        if (nickName != null && !nickName.isEmpty()) {
            newUserDO.setNickName(nickName);
        }
        // 当前管理员 ID 设置
        long by = -1L;
        newUserDO.setCreateBy(by);
        newUserDO.setUpdateBy(by);
        // 当前时间设置
        LocalDateTime now = LocalDateTime.now();
        newUserDO.setCreateTime(now);
        newUserDO.setUpdateTime(now);
        // 构建完毕 保存至数据库
        this.baseMapper.insert(newUserDO);
        return R.success().msg("用户新增成功");
    }
}
